home *** CD-ROM | disk | FTP | other *** search
- ;exe format. demonstrates OOP. B.Kauler 1991
- ;Note that this listing is very cluttered with comments and suggestions.
- ;after basically digesting them you might like to erase them, to be
- ;able to more clearly see the overall program.
- ;
- ;...................................................
- stack1 SEGMENT stack 'stack'
- db 128 DUP(0)
- stack1 ENDS
- ;...................................................
- data SEGMENT 'data'
- ; ......
- ;The structure SHAPES contains "variables" and also
- ;pointers to methods -- but note that we cannot specify the
- ;the address of a method, as MASM will not accept a forward
- ;reference from within a STRUC.
- ;(A solutiion is to put the STRUC definitions after the code is
- ; assembled, but that introduces other problems).
- ;The STRUC definition below is only used by Asm -- it is the
- ;instances that are actually assembled (BOX1, BOX2). When
- ;defining the instances we can initialise the fields, including
- ;insertion of the procedure addresses for each method.
- ;(Note that in the case of dynamically allocated objects, the
- ; pointers would have to be inserted by code, and if they are
- ; far pointers then the structure would have to use DD).
- ;Note that TASM allows nested STRUCs and MASM doesn't. The definition
- ;of BOX below shows the case for TASM, which is conceptually neater.
- ;the comment alongside shows what you would have to replace it with
- ;for MASM. Either way, there is a problem when you come to declare
- ;instances, as you cannot initialise the fields inherited from SHAPE
- ;(only the first field). Whatever fields have been declared in BOX
- ;can be initialised (in this case there's just one; ROUNDED).
- ;hence the rather messy macro (that I've called "instance_box").
- ;Note also that TASM has an "ideal mode" in which structure field-
- ;labels are local to that structure, thus allowing other structures
- ;to have identical labels -- which is what we ideally want for OOP --
- ;but the NOW override no longer works -- perhaps someone can find a
- ;fix for this. At the moment, structure field-labels are global.
-
- SHAPES STRUC
- REDRAW DW ? ;dummy pointer. **see below
- VERT DB 5
- HORIZ DB 10
- SYZE DW ? ;near pointer to SIZE_SHAPES **see below
- ROW DB 0
- COL DB 0
- PLACE DW ? ;near pointer to PLACE_SHAPES **see below
- SHAPES ENDS
- ;** the pointers would have to be Define
- ;Doubleword (DD) if program has multiple
- ;code segments.
-
- ; .......
- BOX STRUC
- SHAPES <> ;TASM only. MASM; replace with (SIZE SHAPES) DUP(?)
- ROUNDED DB 0
- BOX ENDS
- ; .....
- ;macro to create instance of BOX, with data initialisations....
- ;(messy, due to limitations of Asm -- have to create an instance of BOX
- ; then overwrite part of it with an instance of SHAPES)
- MAKE_BOX MACRO ibox
- ibox BOX < ,0> ;cant initialise SHAPE's inherited data here.
- ORG ibox ;backtrack.
- SHAPES <REDRAW_BOX,,,SIZE_SHAPES,2,5,PLACE_SHAPES>
- ORG ibox+(SIZE BOX) ;ret. location ptr to normal position.
- ENDM
-
- ;create instances of BOX....
- MAKE_BOX BOX1
- MAKE_BOX BOX2
-
- ; ......
- NOW EQU [bx] ;es:[bx] required for multiple data segments. see below.
- ;note: TASM treats "THIS" as reserved word, so use NOW.
- ; .....
- data ENDS
-
- ;........................................................
- code SEGMENT 'code'
- ASSUME cs:code
- ; ......
- NOWIS MACRO instance_label
- mov bx,OFFSET instance_label
-
- ;note: For multiple data segments, ES:BX must be loaded, by replacing
- ; the above code with the instruction below, however
- ; instance_label is no longer the actual address loaded to ES:BX
- ; but is the label of a memory location that contains the
- ; far address.(instance_label DD far_address).
- ; Extra steps are required to set up the program for this.
- ; les bx,instance_label
-
- ENDM
- ; ......
- ;..........................................................
- main PROC FAR
- mov ax,data
- mov ds,ax
- ASSUME ds:data
- ; .......
- ; .....
- NOWIS BOX1
- mov dx,0105h ;change row & col
- call NOW.PLACE ;update ROW & COL of BOX1.
- call NOW.REDRAW ;display the box.
-
- ;note: at this point should only call those methods belonging to BOX1.
- ; If you want to call CIRCLE1.REDRAW (for example), first execute
- ; NOWIS CIRCLE1
-
- ;note2: procedure calls to execute only one or two instructions, is
- ; very wasteful, and C++ optimises this situation by treating
- ; some small methods like macros, expanding them in-line.
- ; Thus, although it is not good OOP practice, you can do what
- ; C++ does anyway -- instead of calling PLACE, just put the two
- ; instructions straight in
- ; -- or define the method as a macro. No, don't do it.
-
- ;note3: one thing you may have noticed in the Figure (textbook
- ; hierarchy diagram of the objects) is that I created variable
- ; ROUNDED, attached to BOX, but I did not create a method for it.
- ; I should have, as all data must only be changed by methods
- ; attached to the same object. However I left the Figure
- ; uncluttered as I haven't actually implemented any setting
- ; of ROUNDED in this demo program.
-
- NOWIS BOX2
- mov dx,1020h ;row & col
- call NOW.PLACE
- call NOW.REDRAW ;draws box2
-
- mov ax,4C00h ;back to DOS
- int 21h
- main ENDP
- ;...........................................................
- PLACE_SHAPES PROC NEAR
- ;the new row and column coordinates are
- ;passed to PLACE via DX. DH=row (0-24)
- ;DL=column (0-79).
- mov NOW.ROW,dh
- mov NOW.COL,dl
-
- ;note: a method can call other methods, even methods belonging to
- ; other objects. The standard rule is always use NOWIS before
- ; calling any object that is not the current one.
-
- ret
- PLACE_SHAPES ENDP
- ;..........................................................
- REDRAW_BOX PROC NEAR
- ;no parameters passed to this one. It just
- ;uses ROW, COL, VERT, HORIZ
- ;& ROUNDED to redraw the box.
- ;note again that NOW override is used to
- ;access only the data at the currently pointed
- ;-to instance.
- ; ......
- ;some code here to draw box on scrn....
-
- ;note: don't forget when writing code that BX (or ES:BX) is/are used
- ; for the NOW override, which means that we have to save it/them
- ; if we want to use it/them for anything else.
-
- mov dh,NOW.ROW
- mov ch,0
- mov cl,NOW.VERT
-
- vertloop:
- mov dl,NOW.COL
- push cx ;save vert loop count
- mov ch,0
- mov cl,NOW.HORIZ ;horiz loop count
- push bx ;save NOW override
-
- horizloop:
- push cx ;save horiz loop count
- mov bh,0
- mov ah,2 ;set_cursor
- int 10h
- mov cx,1
- mov al,219 ;ibm block-character.
- mov bx,0003h ;page, colour.
- mov ah,0Ah ;write_char
- int 10h
- pop cx ;restore horiz loop count
- inc dl ;row no. for set_cursor
- loop horizloop ;next horizontal char
-
- pop bx ;restore NOW override
- pop cx ;restore vert loop count
- inc dh ;col no. for set_cursor
- loop vertloop ;next line
- ; ......
- ret
- REDRAW_BOX ENDP
- ;..........................................................
- SIZE_SHAPES PROC NEAR
- ;perhaps this could have some parameters
- ;passed to it, to update VERT & HORIZ,
- ;then return with a pass/fail in AX.
- ; ......
- ; .....
- ret
- SIZE_SHAPES ENDP
- ;.......................................................
-
- code ENDS
- END main
-
- ;NOTE ON USING TURBO-DEBUGGER:
- ; The debugger's Watch window is particularly nice for viewing
- ; all the data for an object, since all you have to do is change
- ; to the Watch window by pressing <F6> then type the name of the
- ; instance you want to view, for example "BOX1".